using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using NAudio.Wave;
using BodySoundSimulator.WavePlayInterface;

namespace BodySoundSimulator.Recording
{
    public partial class SimpleWavePlayer : Form
    {
        #region Fields
        string fileName;
        IWavePlayer waveOut;
        WaveStream mainOutputStream;
        WaveChannel32 volumeStream;
        #endregion

        #region Constructors
        public SimpleWavePlayer(string fileName)
        {
            InitializeComponent();
            this.fileName = fileName;
            UpdateUI();
        }
        #endregion

        #region UI event handlers
        private void btnClose_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.OK;
        }

        private void btnPlayBack_Click(object sender, EventArgs e)
        {
            PlaySelectedWaveFile();
            UpdatePlayerButtons(PlaybackState.Playing);
        }

        private void btnPause_Click(object sender, EventArgs e)
        {
            PausePlayingFile();
            UpdatePlayerButtons(PlaybackState.Paused);
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            StopPlayingFile();
            UpdatePlayerButtons(PlaybackState.Stopped);
        }

        private void timerManager_Tick(object sender, EventArgs e)
        {
            if (waveOut != null)
            {
                if (mainOutputStream.Position >= mainOutputStream.Length)
                {
                    StopPlayingFile();
                    UpdatePlayerButtons(PlaybackState.Stopped);
                }
                else
                {
                    TimeSpan currentTime = mainOutputStream.CurrentTime;
                    this.trackBarTrack.Value = (int)currentTime.TotalSeconds;
                }
            }
        }

        private void SimpleWavePlayer_FormClosing(object sender, FormClosingEventArgs e)
        {
            CloseWaveOut();
        }

        private void trackBarVolume_Scroll(object sender, EventArgs e)
        {
            if (mainOutputStream != null)
            {
                volumeStream.Volume = (float)this.trackBarVolume.Value / 10f;
            }
        }
    
        #endregion

        #region Private methods

        private void UpdateUI()
        {
            this.txtFileName.Text = fileName;
        }

        private void PlaySelectedWaveFile()
        {
            if (waveOut != null)
            {
                if (waveOut.PlaybackState == PlaybackState.Playing)
                {
                    return;
                }
                else if (waveOut.PlaybackState == PlaybackState.Paused)
                {
                    waveOut.Play();
                    return;
                }
            }
            try
            {
                CreateWaveOut();
            }
            catch (Exception driverCreateException)
            {
                MessageBox.Show(String.Format("{0}", driverCreateException.Message));
                return;
            }

            mainOutputStream = CreateInputStream(fileName);
            this.trackBarTrack.Maximum = (int)mainOutputStream.TotalTime.TotalSeconds;
            this.trackBarTrack.TickFrequency = this.trackBarTrack.Maximum / 30;

            try
            {
                waveOut.Init(mainOutputStream);
            }
            catch (Exception initException)
            {
                MessageBox.Show(String.Format("{0}", initException.Message), "Error Initializing Output");
                return;
            }

            // not doing Volume on IWavePlayer any more
            //volumeStream.Volume = (float)this.trackBarVolume.Value / 10;
            volumeStream.Volume = 4;
            waveOut.Play();
        }

        private void PausePlayingFile()
        {
            if (waveOut != null)
            {
                if (waveOut.PlaybackState == PlaybackState.Playing)
                {
                    waveOut.Pause();
                }
            }
        }

        private void StopPlayingFile()
        {
            if (waveOut != null)
            {
                waveOut.Stop();
                this.trackBarTrack.Value = 0;
                CloseWaveOut();
            }
        }

        private void CreateWaveOut()
        {
            CloseWaveOut();
            WaveCallbackInfo callbackInfo = WaveCallbackInfo.NewWindow();
            WaveOut outputDevice = new WaveOut(callbackInfo);
            waveOut = outputDevice;
        }

        private void CloseWaveOut()
        {
            if (waveOut != null)
            {
                waveOut.Stop();
            }
            if (mainOutputStream != null)
            {
                volumeStream.Close();
                volumeStream = null;
                mainOutputStream.Close();
                mainOutputStream = null;
            }
            if (waveOut != null)
            {
                waveOut.Dispose();
                waveOut = null;
            }
        }

        private WaveStream CreateInputStream(string fileName)
        {
            WaveChannel32 inputStream;
            if (fileName.EndsWith(".wav"))
            {
                WaveStream readerStream = new WaveFileReader(fileName);
                if (readerStream.WaveFormat.Encoding != WaveFormatEncoding.Pcm)
                {
                    readerStream = WaveFormatConversionStream.CreatePcmStream(readerStream);
                    readerStream = new BlockAlignReductionStream(readerStream);
                }
                if (readerStream.WaveFormat.BitsPerSample != 16)
                {
                    WaveFormat format = new WaveFormat(readerStream.WaveFormat.SampleRate,
                        16, readerStream.WaveFormat.Channels);
                    readerStream = new WaveFormatConversionStream(format, readerStream);
                }
                inputStream = new WaveChannel32(readerStream);
            }
            else
            {
                throw new InvalidOperationException("Unsupported extension");
            }
            // we are not going into a mixer so we don't need to zero pad
            //((WaveChannel32)inputStream).PadWithZeroes = false;
            volumeStream = inputStream;
            MeteringStream meteringStream = new MeteringStream(inputStream, inputStream.WaveFormat.SampleRate / 10);
            meteringStream.StreamVolume += new EventHandler<StreamVolumeEventArgs>(meteringStream_StreamVolume);

            return meteringStream;
        }

        private void UpdatePlayerButtons(PlaybackState state)
        {
            switch (state)
            {
                case PlaybackState.Playing:
                    this.btnPlayBack.Enabled = false;
                    this.btnStop.Enabled = true;
                    this.btnPause.Enabled = true;
                    break;
                case PlaybackState.Paused:
                    this.btnPlayBack.Enabled = true;
                    this.btnStop.Enabled = true;
                    this.btnPause.Enabled = false;
                    break;
                case PlaybackState.Stopped:
                    this.btnPlayBack.Enabled = true;
                    this.btnStop.Enabled = false;
                    this.btnPause.Enabled = false;
                    break;
            }
        }

        private void meteringStream_StreamVolume(object sender, StreamVolumeEventArgs e)
        {
            this.waveformPainter1.AddMax(e.MaxSampleValues[0]);
            if (e.MaxSampleValues.Length > 1)
            {
                waveformPainter2.AddMax(e.MaxSampleValues[1]);
            }

        }
        #endregion
    }
}